import java.io.*;
import java.net.*;
import java.util.Scanner;

/**
 * @author Braintrust ELITE
 */
public class ATMServerThread extends Thread {
	private Socket				socket	= null;
	private DataOutputStream	out		= null;
	private DataInputStream		in		= null;

	private ATMAccount			account;

	public ATMServerThread(Socket socket) {
		super("ATMServerThread");
		this.socket = socket;
	}

	public void run() {
		try {
			out = new DataOutputStream(socket.getOutputStream());
			in = new DataInputStream(socket.getInputStream());

			this.account = ATMAccounts.getATMAccounts().getAccount(getAccountNumber());
			checkPassword(this.account);
			updateLanguage();
			sendMOTD();

			// main loop
			Boolean doRun = true;
			while (doRun) {
				new ATMPacket(ATMPacket.INT_DISP_SWITCH, 1).writeOut(out);
				int menuChoice = getInt();
				switch (menuChoice) {
					case (1): // balance
						(new ATMPacket(ATMPacket.INT_DISP_NUMBER, account.getBalance())).writeOut(out);
						break;
					case (2): // withdraw
						(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 2)).writeOut(out);
						int amount = getInt();
						(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 9)).writeOut(out);
						if (!account.checkOneTimeCode(getInt())) {
							(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 10)).writeOut(out);
							break;
						}

						if (account.withdraw(amount))
							(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 4)).writeOut(out);
						else
							(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 5)).writeOut(out);
						break;
					case (3): // deposit
						(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 3)).writeOut(out);
						if (account.deposit(getInt()))
							(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 4)).writeOut(out);
						else
							(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 5)).writeOut(out);
						break;
					case (4): // language
						(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 8)).writeOut(out);
						switch (getInt()) {
							case (1):
								account.setLanguage(ATMAccount.Language.ENG);
								break;
							case (2):
								account.setLanguage(ATMAccount.Language.SWE);
								break;
							default:
						}
						updateLanguage();
						break;
					case (5): // exit
						(new ATMPacket(ATMPacket.INT_DISP_SWITCH, 6)).writeOut(out);
						(new ATMPacket(ATMPacket.REQUEST_SHUTDOWN)).writeOut(out);
						doRun = false;
						break;
					default:
						break;
				}
			}

			socket.close();
		} catch (SocketException se) {
			System.err.println("Client exited unexpectedly!");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void sendMOTD() throws Exception {
		// Read MOTD from file
		Scanner file = new Scanner(new File("motd"));
		String welcome = file.nextLine();
		file.close();
		// Send the MOTD
		if (welcome.length() > 80)
			welcome = welcome.substring(0, 79);
		(new ATMPacket(ATMPacket.STR_CONTAINER, welcome)).writeOut(out);
	}

	private int getInt() throws Exception {
		ATMPacket p = null;
		(new ATMPacket(ATMPacket.REQUEST_INT)).writeOut(out);
		p = ATMPacket.readIn(in);
		while (p.getPacketType() != ATMPacket.INT_CONTAINER) {
			(new ATMPacket(ATMPacket.CMD_NOK)).writeOut(out);
			p = ATMPacket.readIn(in);
		}
		return p.getIntData();
	}

	private void updateLanguage() throws Exception {
		// send new language data if clients differs from serverside version
		(new ATMPacket(ATMPacket.REQUEST_LANG)).writeOut(out);
		ATMPacket p = ATMPacket.readIn(in);
		if (p.getPacketType() != ATMPacket.INT_CONTAINER)
			System.err.println("FEL PAKET!");
		if (p.getIntData() != (account.getLangStr().hashCode())) {
			System.out.println("sending language data");
			(new ATMPacket(ATMPacket.STR_NEW_LANG, account.getLangStr())).writeOut(out);
		}
	}

	private int getAccountNumber() throws Exception {
		ATMPacket p = ATMPacket.readIn(in);
		while (p.getPacketType() != ATMPacket.INT_ACCOUNT_NUMBER) {
			(new ATMPacket(ATMPacket.CMD_NOK)).writeOut(out);
			p = ATMPacket.readIn(in);
		}
		(new ATMPacket(ATMPacket.CMD_OK)).writeOut(out);
		return p.getIntData();
	}

	private boolean checkPassword(ATMAccount account) throws Exception {
		// Checks the password
		ATMPacket p;
		boolean passOk = false;
		while (passOk == false) {
			p = ATMPacket.readIn(in);
			while (p.getPacketType() != ATMPacket.INT_PASS_CODE) {
				(new ATMPacket(ATMPacket.CMD_NOK)).writeOut(out);
				p = ATMPacket.readIn(in);
			}
			if (account.verifyPassword(p.getIntData())) {
				passOk = true;
				(new ATMPacket(ATMPacket.CMD_OK)).writeOut(out);
			} else if (account.getPassword() == 0) {
				account.setPassword(p.getIntData());
				passOk = true;
				(new ATMPacket(ATMPacket.CMD_OK)).writeOut(out);
			} else {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				(new ATMPacket(ATMPacket.CMD_NOK)).writeOut(out);
			}
		}
		return true;
	}
}
